package com.chatsimple.netty.task

import com.chatsimple.logDebug
import com.chatsimple.netty.*
import com.chatsimple.netty.task.usecase.GetClientsInfoUseCase
import com.chatsimple.netty.task.usecase.UnHandleError
import com.chatsimple.netty.task.usecase.UseCase
import com.google.protobuf.ByteString
import com.google.protobuf.Message
import com.ly.data.FuncProto.Func
import com.ly.data.MessageProtobuf.*
import io.netty.channel.Channel


class RequestHandler : ITaskHandler {

    private val useCases: Map<Func, UseCase> = mapOf(
        Func.GetClientsInfo to GetClientsInfoUseCase(this)
    )

    override fun handle(channel: Channel, task: TaskProto) {
        if (task.type != TaskType.Request) return
        val request = try {
            Req.parseFrom(task.data)
        } catch (e: Exception) {
            channel.reportError(CODE_ERROR_PARSE_FAILED, task)
            return
        }
        try {
            val result = (useCases[request.method] ?: throw UnHandleError(
                code = CODE_PARAM_ERROR, msg = findMsg(CODE_PARAM_ERROR)
            )).handle(request.param)
            channel.ack(origTask = task, data = result)
        } catch (e: UnHandleError) {
            logDebug("func = ${request.method} 业务处理失败 ${e.message}")
            channel.reportError(e.code, task)
        } catch (e: Exception) {
            logDebug("func = ${request.method} 发生未知错误 ${e.message}")
            channel.reportError(CODE_HANDLE_ERROR, task)
        }

    }


    private fun Channel.reportError(code: Int, task: TaskProto) {
        val errorMsg = findMsg(code)
        val resp = task.toBuilder()
            .setType(TaskType.Response)
            .setData(
                Resp.newBuilder()
                    .setData(ByteString.EMPTY)
                    .setCode(code)
                    .setMsg(errorMsg)
                    .build().toByteString()
            ).build()
        writeAndFlush(resp).addListener {
            logDebug("RequestHandler seq = ${task.seq} reportError($code,$errorMsg) 应答结果:${it.isSuccess}")
        }
    }


    private fun Channel.ack(
        origTask: TaskProto,
        data: Message?,
        code: Int = CODE_SUCCESS,
        msg: String = findMsg(code)
    ) {
        writeAndFlush(
            origTask.buildResponse(
                localAddress().toString(), Resp.newBuilder()
                    .setCode(code)
                    .setMsg(msg)
                    .setData(data?.toByteString() ?: ByteString.EMPTY)
                    .build().toByteString()
            )
        ).addListener {
            logDebug("RequestHandler seq = ${origTask.seq} ack(${code},${msg}) 应答${if (it.isSuccess) "成功" else "失败"} ,response:$data")
        }
    }

    private fun TaskProto.buildResponse(from: String, byteString: ByteString): TaskProto {
        return toBuilder()
            .setType(TaskType.Response)
            .setFrom(from)
            .setData(byteString)
            .build()
    }

    override fun destroy(channel: Channel?) {

    }
}